﻿using System;
using System.ComponentModel;
using System.Threading;
using Microsoft.Practices.Unity.InterceptionExtension;
using Sapit.Helpers;
using Sapit.Unity.Attributes;

namespace Sapit.Unity
{
    public class TimeoutHandler : ICallHandler
    {
        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            var timeout = AttributeHelper.GetAttributeIfPresent<TimeoutAttribute>(input.MethodBase);
            if (timeout != null)
            {
                BackgroundWorker worker = new BackgroundWorker();
                worker.WorkerSupportsCancellation = true;
                IMethodReturn result = null;
                worker.DoWork += (sender, e) =>
                {
                    result = getNext()(input, getNext);
                };
                worker.RunWorkerAsync();
                DateTime startTime = DateTime.Now;
                DateTime maxEndTime = startTime.AddMilliseconds(timeout.TimeoutMilliseconds);
                while (result == null && DateTime.Now < maxEndTime)
                {
                    Thread.Sleep(50);
                }
                if (result == null)
                {
                    worker.CancelAsync();
                    worker.Dispose();
                    return input.CreateExceptionMethodReturn(new TimeoutException(string.Format("Timeout expired. Operation took longer than {0} milliseconds.", timeout.TimeoutMilliseconds)));
                }
                else
                {
                    return result;
                }
            }
            else
            {
                return getNext()(input, getNext);
            }
        }

        public int Order { get; set; }
    }
}
